#ifndef F_CORE_H
#define F_CORE_H 1

#include <tcl.h>

#ifdef BUILD_F
#  undef TCL_STORAGE_CLASS
#  define TCL_STORAGE_CLASS DLLEXPORT
#endif


// элементарная ячейка данных 
typedef struct Cons {
    struct Cons *next;
    Tcl_Obj *obj;
} Cons;

Cons *consAlloc(Tcl_Obj *); // выделить ячейку для хранения объекта
Cons *consFree(Cons *);     // удалить ячейку
Cons *consClone(Cons *from,Cons *to,Cons **saveTail); // дублировать цепочку ячеек
Cons *consFirst(Cons *from,Cons *to);   // вернуть первую значащую ячейку
Cons *consLast(Cons *from,Cons *to);   // вернуть последнюю значащую ячейку
Cons *consNext(Cons *from,Cons *to);    //  вернуть следующую значащую ячейку

Cons *tupleFirstCons(Tcl_Interp *,Tcl_Obj *);
Cons *tupleNextCons(Tcl_Interp *,Tcl_Obj *,Cons *);

Cons *consExpand(Cons *,Cons **fixtail);    // если cons содержит кортеж, то переместить его следом за cons
void consCollapse(Cons *,Cons *); // ячейки между from и to упаковать в два кортежа

// набор (линейный список) ячеек
// TODO: переделать в линейный кольцевой список, а то так легко tail теряется и много сил уходит на контроль за ним
//       тогда head=tail->next, а свободную часть можно задействовать под счетчик например
typedef struct Tuple {
    Cons *head;
    Cons *tail;
} Tuple;
#define TUPLE(obj) ((Tuple *)&obj->internalRep.twoPtrValue)
extern const Tcl_ObjType *tupleType;

Tcl_Obj *tupleObjNew();
Tcl_Obj *tupleObjFromAny(Tcl_Interp *,Tcl_Obj *);
Tcl_Obj *asTupleObj(Tcl_Interp *interp,Tcl_Obj *obj,int foredit);   // конвертировать объект в tuple, при надобности дублировать

void tupleObjPut(Tcl_Interp *,Tcl_Obj *tupleObj,Tcl_Obj *obj);
void tupleObjPush(Tcl_Interp *,Tcl_Obj *tupleObj,Tcl_Obj *obj);

#define ALLOW_LAZY 1
#define ALLOW_TUPLE 2
Tcl_Obj *tupleObjGet(Tcl_Interp *,Tcl_Obj *tupleObj,int flags);

int tupleObjCmd(ClientData,Tcl_Interp *,int objc,Tcl_Obj * const objv[]);

// "отложенная" процедура
typedef struct Lazy {
    Tcl_Obj *cmd;       // команда для исполнения
    Tcl_Interp *interp; // интерпретатор
    Tcl_Namespace *ns;  // пространство имён
    char *dirty;        // если не NULL, то предварительно должны исполняться все прочие dirty c этим ключом
} Lazy;
#define LAZY(obj) (*(Lazy **)&obj->internalRep.twoPtrValue.ptr1)
extern const Tcl_ObjType *lazyType;

Tcl_Obj *lazyObjNew(Tcl_Interp *,char *dirty,int objc,Tcl_Obj *const objv[],...);
int lazyObjCmd(ClientData data,Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
void lazyObjExec(Tcl_Obj *lazyObj,int processDirty);

extern const Tcl_ObjType *dictType,*listType;

EXTERN int Tuple_Init _ANSI_ARGS_((Tcl_Interp *));

# undef TCL_STORAGE_CLASS
# define TCL_STORAGE_CLASS DLLIMPORT

#endif
